From: ;SPMquot;Zvi Har'El;SPMquot; ;SPMlt;rl@leeor.technion.ac.il;SPMgt; Subject: Re: TeX--XeT and/or working TIE for C

I have a web2c-6.1 version of tex--xet files tex.ch and tex.web. I generated them using the web2c-5.851d files from noa.huji.ac.il, taking into account the changes in web2c from 5.851d to 6.1. I enclose here unified diffs (genrated by gnu diff -U 1), so you can generate the files using patch. If you want the files themselves, let me know and I'll put them in our public ftp directory so you can fetch them.

Zvi. ================================================================================ --- tex.ch.orig Mon Jul 25 16:31:38 1994 +++ tex.ch Mon Jul 25 16:34:00 1994 @@ -610,3 +610,3 @@ @x -wterm(banner); +wterm(TeX_XeT_banner); if format_ident=0 then wterm_ln(' (no format preloaded)') @@ -1095,3 +1095,3 @@ @x -begin wlog(banner); +begin wlog(TeX_XeT_banner); slow_print(format_ident); print(;SPMquot; ;SPMquot;); @@ -1981,10 +1981,5 @@ @x -This section should be replaced, if necessary, by any special +The following sections, as recommended, contain the more extensive modifications of the program that are necessary to make TEX work at a particular installation. -It is usually best to design your change file so that all changes to -previous sections preserve the section numbering; then everybody's version -will be consistent with the published program. More extensive changes, -which introduce new sections, can be inserted here; then only the index -itself will get a new section number. @^system dependencies@;SPMgt; --- tex.web.orig Mon Jul 25 16:31:39 1994 +++ tex.web Mon Jul 25 18:28:20 1994 @@ -44,2 +44,3 @@ 1 +2

@@ -60,2 +61,20 @@ =3 ++5 +6 +7 +8 +9 +10 +11 +12 +13 +14 + + 15 + 16 +17 + 18 + 19 + @@ -124,2 +143,5 @@

+@d TeX_XeT_version=='--1.0' <#7#>identifies the current TeX--XeT version<#7#> +@d TeX_XeT_copyright=='TeX--XeT Copyright (C) 1992 by Dante e.V.' + @ The present implementation has a long ancestry, beginning in the summer @@ -177,5 +199,28 @@

-If this program is changed, the resulting system should not be called -`TEX'; the official name `TEX' by itself is reserved -for software systems that are fully compatible with each other. + +This program contains code for mixed left-to-right and right-to-left +typesetting. This code is inspired by but different from TEX-<#106#>EX<#106#> as +presented by Donald~E. Knuth and Pierre MacKay in <#8#>TUGboat<#8#> +@^Knuth, Donald Ervin@;SPMgt; +@^MacKay, Pierre@;SPMgt; +<#9#>8<#9#>, 14--25, 1987. Since the original program is changed, the +resulting system is not called `TEX'; the official name `TEX' by +itself is reserved for software systems that are fully compatible with +each other. + +In order to avoid confusion with TEX-<#107#>EX<#107#> the present implementation of +mixed direction typesetting is called TEX-<#108#>EX-<#108#>. It differs from TEX-<#109#>EX<#109#> +in several important aspects: +(1)~Right-to-left text is reversed explicitely by the |ship_out| routine +and is written to a normal ḊVI file without any |begin_reflect| or +|end_reflect| commands; (2)~a |math_node| is (ab)used instead of a +|whatsit_node| to record the Ḃ beginL, Ḃ endL, Ḃ beginR, and +Ḃ endR text direction primitives in order not to influence the line +breaking algorithm for pure left-to-right text; (3)~therefore TEX-<#110#>EX-<#110#> +is designed to be used instead of and not in addition to TEX and +consequently the pool file name is not changed; (4)~right-to-left text +interrupted by a displayed equation is automatically resumed after that +equation; and (5)~the |valign| command code with a non-zero command +modifier is (ab)used for the text direction primitives. + A special test suite called the ``ṪRIP test'' is available for @@ -183,3 +228,3 @@ known as `TEX' [cf.~Stanford Computer Science report CS1027, -November 1984]. +November 1984]. As a consequence of points~(1) and~(2) above TEX-<#111#>EX-<#111#>

@@ -218,2 +263,7 @@

+@d TeX_XeT_banner=='This is TeX--XeT', + ', Version 3.141' <#16#>here we should use a substring of banner<#16#> + ,TeX_XeT_version <#17#>printed when TEX starts<#17#> + + @ The program begins with a normal Pascal program heading, whose @@ -1554,3 +1604,3 @@ @;SPMlt;Initialize the output...@;SPMgt;= -wterm(banner); +wterm(TeX_XeT_banner); if format_ident=0 then wterm_ln(' (no format preloaded)') @@ -1558,2 +1608,3 @@ end; +wterm_ln(TeX_XeT_copyright); <#18#>may be omitted under certain circumstances<#18#> update_terminal; @@ -3069,2 +3120,6 @@

+In addition a |math_node| with |subtype;SPMgt;after| and |width=0| will be +(ab)used to record one of the text direction primitives ( Ḃ beginL, +Ḃ endL, Ḃ beginR, Ḃ endR ). + @d math_node=9 <#23#>|type| of a math node<#23#> @@ -3072,2 +3127,13 @@ @d after=1 <#24#>|subtype| for math node that winds up a formula<#24#> +@# +@d L_code=2 +@d begin_L_code=L_code+before <#91#>|subtype| for Ḃ beginL `math node'<#91#> +@d end_L_code=L_code+after <#92#>|subtype| for Ḃ endL `math node'<#92#> +@d R_code=4 +@d begin_R_code=R_code+before <#93#>|subtype| for Ḃ beginR `math node'<#93#> +@d end_R_code=R_code+after <#94#>|subtype| for Ḃ endR `math node'<#94#> +@# +@d end_LR(#)==odd(subtype(#)) +@d end_LR_type(#)==(subtype(#)+after-before) +@d begin_LR_type(#)==(info(#)-after+before)

@@ -3544,3 +3610,4 @@ glue_node: if glue_ptr(p);SPMlt;;SPMgt;zero_glue then print_char(;SPMquot; ;SPMquot;); -math_node: print_char(;SPMquot;#math20#;SPMquot;); + mathnode : ifsubtype(p) ;SPMgt; afterthenprint(;SPMquot;[];SPMquot;) + elseprintchar(;SPMquot;;SPMquot;); ligature_node: short_display(lig_ptr(p)); @@ -3809,3 +3876,9 @@ @ @;SPMlt;Display math node |p|@;SPMgt;= -begin print_esc(;SPMquot;math;SPMquot;); +if subtype(p);SPMgt;after then + begin if odd(subtype(p)) then print_esc(;SPMquot;end;SPMquot;) + else print_esc(;SPMquot;begin;SPMquot;); + if subtype(p);SPMlt;=end_L_code then print_char(;SPMquot;L;SPMquot;) + else print_char(;SPMquot;R;SPMquot;); + end +else begin print_esc(;SPMquot;math;SPMquot;); if subtype(p)=before then print(;SPMquot;on;SPMquot;) @@ -4089,3 +4162,4 @@ @d halign=32 <#95#>horizontal table alignment ( Ḃ halign )<#95#> -@d valign=33 <#96#>vertical table alignment ( Ḃ valign )<#96#> +@d valign=33 <#97#>vertical table alignment ( Ḃ valign ) or text + direction ( Ḃ beginL, Ḃ endL, Ḃ beginR, Ḃ endR )<#97#> @d no_align=34 <#98#>temporary escape from alignment ( Ḃ noalign )<#98#> @@ -4290,2 +4364,4 @@ In horizontal mode, the |prev_graf| field is used for initial language data. +A nineth quantity, |LR_save|, holds the LR stack when a paragraph is +interrupted by a displayed formula.

@@ -4305,2 +4381,3 @@ @!aux_field: memory_word; + @!LRs_field: halfword; end; @@ -4317,2 +4394,3 @@ @d mode_line==cur_list.ml_field <#37#>source file line number at beginning of list<#37#> +@d LR_save==cur_list.LRs_field <#38#>LR stack when a paragraph is interrupted<#38#>

@@ -4342,2 +4420,3 @@ prev_depth:=ignore_depth; mode_line:=0; +LR_save:=null; prev_graf:=0; shown_mode:=0; @@ -4357,2 +4436,3 @@ incr(nest_ptr); head:=get_avail; tail:=head; prev_graf:=0; mode_line:=line; +LR_save:=null; end; @@ -5712,2 +5792,10 @@ @!@:valign_<#105#><#99#>Ḃ valign primitive@;SPMgt; +primitive(;SPMquot;beginL;SPMquot;,valign,begin_L_code);@/ +@!@:beginL_<#99#><#100#>Ḃ beginL primitive@;SPMgt; +primitive(;SPMquot;endL;SPMquot;,valign,end_L_code);@/ +@!@:endL_<#100#><#101#>Ḃ endL primitive@;SPMgt; +primitive(;SPMquot;beginR;SPMquot;,valign,begin_R_code);@/ +@!@:beginR_<#101#><#102#>Ḃ beginR primitive@;SPMgt; +primitive(;SPMquot;endR;SPMquot;,valign,end_R_code);@/ +@!@:endR_<#102#><#103#>Ḃ endR primitive@;SPMgt; primitive(;SPMquot;vcenter;SPMquot;,vcenter,0);@/ @@ -5764,3 +5852,9 @@ vadjust: print_esc(;SPMquot;vadjust;SPMquot;); -valign: print_esc(;SPMquot;valign;SPMquot;); +valign: if chr_code;SPMlt;;SPMgt;0 then case chr_code of + begin_L_code: print_esc(;SPMquot;beginL;SPMquot;); + end_L_code: print_esc(;SPMquot;endL;SPMquot;); + begin_R_code: print_esc(;SPMquot;beginR;SPMquot;); + othercases print_esc(;SPMquot;endR;SPMquot;) + endcases +else print_esc(;SPMquot;valign;SPMquot;); vcenter: print_esc(;SPMquot;vcenter;SPMquot;); @@ -10322,3 +10416,3 @@ @ @;SPMlt;Print the banner...@;SPMgt;= -begin wlog(banner); +begin wlog(TeX_XeT_banner); slow_print(format_ident); print(;SPMquot; ;SPMquot;); @@ -12238,3 +12332,25 @@

-@d synch_h==if cur_h;SPMlt;;SPMgt;dvi_h then +For mixed direction text (TEX-<#112#>EX-<#112#>) the current text direction is called +|cur_dir|. As the box being shipped out will never be used again and +soon be recycled, we can simply reverse any R-text (i.e., right-to-left) +segments of hlist nodes as well as complete hlist nodes embedded in such +segments. Moreover this can be done iteratively rather than recursively. +There are, however, two complications related to leaders which require +some additional bookkeeping: (1)~One and the same hlist node might be +used more than once (but never inside both L- and R-text); and +(2)~leader boxes inside hlists must be aligned with respect to the left +edge of the original hlist. + +A math node is changed into a kern node whenever the text direction +remains the same, it is replaced by an |edge_node| if the text direction +changes; an |hlist_node| inside R-text is changed to an |R_node| once +its hlist has been reversed. +@!@^data structure assumptions@;SPMgt; + + @d R_node=unset_node <#44#>an |unset_node| does not occur during |ship_out|<#44#> + @d left_to_right=0 + @d right_to_left=1 + @d reflected==1-cur_dir <#45#>the opposite of |cur_dir|<#45#> + @# + @d synch_h==if cur_h;SPMlt;;SPMgt;dvi_h then begin movement(cur_h-dvi_h,right1); dvi_h:=cur_h; @@ -12250,2 +12366,4 @@ @!cur_s:integer; <#46#>current depth of output box nesting, initially -1<#46#> +@!cur_dir:small_number; <#47#>current text direction<#47#> +@!LR_ptr:pointer; <#48#>stack of LR codes<#48#>

@@ -12306,3 +12424,4 @@ @!outer_doing_leaders:boolean; <#49#>were we doing leaders?<#49#> -@!edge:scaled; <#50#>left edge of sub-box, or right edge of leader space<#50#> +@!edge:scaled; <#51#>right edge of sub-box or leader space<#51#> +@!prev_p:pointer; <#52#>one step behind |p|<#52#> begin this_box:=temp_ptr; g_order:=glue_order(this_box); @@ -12313,2 +12432,5 @@ save_loc:=dvi_offset+dvi_ptr; base_line:=cur_v; left_edge:=cur_h; +prev_p:=this_box+list_offset; +if cur_dir=right_to_left then if type(this_box)=hlist_node then + @;SPMlt;Reverse the complete hlist and change this node into an |R_node|@;SPMgt;; while p;SPMlt;;SPMgt;null do @;SPMlt;Output node |p| for |hlist_out| and move to the next node, @@ -12334,3 +12456,3 @@ cur_h:=cur_h+char_width(f)(char_info(f)(c)); - p:=link(p); + prev_p:=p; p:=link(p); until not is_char_node(p); @@ -12353,3 +12475,3 @@ begin case type(p) of -hlist_node,vlist_node:@;SPMlt;Output a box in an hlist@;SPMgt;; +hlist_node,vlist_node,R_node:@;SPMlt;Output a box in an hlist@;SPMgt;; rule_node: begin rule_ht:=height(p); rule_dp:=depth(p); rule_wd:=width(p); @@ -12359,4 +12481,10 @@ glue_node: @;SPMlt;Move right or output leaders@;SPMgt;; -kern_node,math_node:cur_h:=cur_h+width(p); +kern_node:cur_h:=cur_h+width(p); +math_node: + begin @;SPMlt;Adjust the LR stack for the |ship_out| routine; if necessary + reverse an hlist segment and |goto reswitch||@;SPMgt;; + cur_h:=cur_h+width(p); + end; ligature_node: @;SPMlt;Make node |p| look like a |char_node| and |goto reswitch|@;SPMgt;; +@;SPMlt;Cases of |hlist_out| that arise in mixed direction text only@;SPMgt;@; othercases do_nothing @@ -12366,3 +12494,3 @@ move_past: cur_h:=cur_h+rule_wd; -next_p:p:=link(p); +next_p:prev_p:=p; p:=link(p); end @@ -12373,6 +12501,7 @@ cur_v:=base_line+shift_amount(p); <#53#>shift the box down<#53#> - temp_ptr:=p; edge:=cur_h; + temp_ptr:=p; edge:=cur_h+width(p); + if cur_dir=right_to_left then cur_h:=edge; if type(p)=vlist_node then vlist_out@+else hlist_out; dvi_h:=save_h; dvi_v:=save_v; - cur_h:=edge+width(p); cur_v:=base_line; + cur_h:=edge; cur_v:=base_line; end @@ -12416,2 +12545,3 @@ begin rule_wd:=rule_wd+10; <#54#>compensate for floating-point rounding<#54#> + if cur_dir=right_to_left then cur_h:=cur_h-10; edge:=cur_h+rule_wd; lx:=0; @@ -12422,3 +12552,5 @@ then advance |cur_h| by |leader_wd+lx|@;SPMgt;; - cur_h:=edge-10; goto next_p; + if cur_dir=right_to_left then cur_h:=edge + else cur_h:=edge-10; + goto next_p; end; @@ -12462,2 +12594,3 @@ synch_h; save_h:=dvi_h; temp_ptr:=leader_box; +if cur_dir=right_to_left then cur_h:=cur_h+leader_wd; outer_doing_leaders:=doing_leaders; doing_leaders:=true; @@ -12509,3 +12642,3 @@ begin case type(p) of -hlist_node,vlist_node:@;SPMlt;Output a box in a vlist@;SPMgt;; +hlist_node,vlist_node,R_node:@;SPMlt;Output a box in a vlist@;SPMgt;; rule_node: begin rule_ht:=height(p); rule_dp:=depth(p); rule_wd:=width(p); @@ -12531,3 +12664,4 @@ save_h:=dvi_h; save_v:=dvi_v; - cur_h:=left_edge+shift_amount(p); <#55#>shift the box right<#55#> + if cur_dir=right_to_left then cur_h:=left_edge-shift_amount(p) + else cur_h:=left_edge+shift_amount(p); <#56#>shift the box right<#56#> temp_ptr:=p; @@ -12543,3 +12677,6 @@ if (rule_ht;SPMgt;0)and(rule_wd;SPMgt;0) then <#57#>we don't output empty rules<#57#> - begin synch_h; synch_v; + begin if cur_dir=right_to_left then cur_h:=cur_h-rule_wd; + synch_h; synch_v; + dvi_out(put_rule); dvi_four(rule_ht); dvi_four(rule_wd); + cur_h:=left_edge; dvi_out(put_rule); dvi_four(rule_ht); dvi_four(rule_wd); @@ -12640,3 +12777,7 @@ end; +cur_dir:=left_to_right; <#58#>L-text at the outer level<#58#> +LR_ptr:=get_avail; info(LR_ptr):=before; <#59#>this will never match<#59#> @;SPMlt;Ship box |p| out@;SPMgt;; +if info(LR_ptr);SPMlt;;SPMgt;before then LR_confusion; +free_avail(LR_ptr); LR_ptr:=null; if tracing_output;SPMlt;=0 then print_char(;SPMquot;];SPMquot;); @@ -12846,3 +12987,7 @@

-@p function hpack(@!p:pointer;@!w:scaled;@!m:small_number):pointer; +@p function safe_info(@!p:pointer): halfword; +begin if p=null then safe_info:=0@+else safe_info:=info(p); +end; +@# +function hpack(@!p:pointer;@!w:scaled;@!m:small_number):pointer; label reswitch, common_ending, exit; @@ -12857,3 +13002,6 @@ @!hd:eight_bits; <#60#>height and depth indices for a character<#60#> -begin last_badness:=0; r:=get_node(box_node_size); type(r):=hlist_node; +@!LR_ptr:pointer; <#61#>stack of LR codes<#61#> +@!LR_problems:integer; <#62#>counts missing begins and ends<#62#> +begin LR_ptr:=null; LR_problems:=0; +last_badness:=0; r:=get_node(box_node_size); type(r):=hlist_node; subtype(r):=min_quarterword; shift_amount(r):=0; @@ -12870,3 +13018,4 @@ for an overfull or underfull hbox@;SPMgt;; -exit: hpack:=r; +exit: @;SPMlt;Check for LR anomalies at the end of |hpack|@;SPMgt;; +hpack:=r; end; @@ -12894,3 +13043,6 @@ glue_node:@;SPMlt;Incorporate glue into the horizontal totals@;SPMgt;; - kern_node,math_node: x:=x+width(p); + kern_node,math_node: + begin x:=x+width(p); + @;SPMlt;Adjust the LR stack for the |hpack| routine@;SPMgt;; + end; ligature_node: @;SPMlt;Make node |p| look like a |char_node| @@ -17014,3 +17166,3 @@ disc_node: @;SPMlt;Try to break after a discretionary fragment, then |goto done5|@;SPMgt;; -math_node: begin auto_breaking:=(subtype(cur_p)=after); kern_break; + math_node: begin auto_breaking:=(subtype(cur_p);SPMlt;;SPMgt;before); kern_break; end; @@ -17200,3 +17352,5 @@ @!cur_line: halfword; <#63#>the current line number being justified<#63#> -begin @;SPMlt;Reverse the links of the relevant passive nodes, setting |cur_p| to the + @!LR_ptr:pointer; <#64#>stack of LR codes<#64#> + begin LR_ptr:=LR_save; + @;SPMlt;Reverse the links of the relevant passive nodes, setting |cur_p| to the first breakpoint@;SPMgt;; @@ -17213,3 +17367,3 @@ @:this can't happen line breaking<#103#><#104#>;SPMnbsp;;SPMnbsp;;SPMnbsp;;SPMnbsp;line breaking@;SPMgt; -prev_graf:=best_line-1; +prev_graf:=best_line-1; LR_save:=LR_ptr; end; @@ -17243,3 +17397,4 @@ if type(q)=kern_node then if subtype(q);SPMlt;;SPMgt;explicit then goto done1; - r:=q; <#65#>now |type(q)=glue_node|, |kern_node|, |math_node| or |penalty_node|<#65#> + r:=q; <#66#>now |type(q)=glue_node|, |kern_node|, |math_node| or |penalty_node|<#66#> + @;SPMlt;Adjust the LR stack for the |post_line_break| routine@;SPMgt;; end; @@ -17260,4 +17415,7 @@ @;SPMlt;Justify the line ending at breakpoint |cur_p|, and append it...@;SPMgt;= +@;SPMlt;Insert LR nodes at the beginning of the current line and adjust + the LR stack based on LR nodes in this line@;SPMgt;; @;SPMlt;Modify the end of the line to reflect the nature of the break and to include Ḃ rightskip; also set the proper value of |disc_break|@;SPMgt;; +@;SPMlt;Insert LR nodes at the end of the current line@;SPMgt;; @;SPMlt;Put the #math21#l
leftskipglueattheleftanddetachthisline@ ;SPMgt; ;@@ - 17283, 3 + 17441, 5@@| discbreak : = true|@ ;SPMgt; - elseif (type(q) = mathnode)or(type(q) = kernnode)thenwidth(q) : = 0; + elseif (type(q) = mathnode)or(type(q) = kernnode)then + beginwidth(q) : = 0;@ ;SPMlt; AdjusttheLRstackforthe| p...@ ;SPMgt; ; + end;end@@ - 21104, 2 + 21264, 5@@elselinebreak(widowpenalty); + ifLRsave ;SPMlt; ;SPMgt; nullthen + beginflushlist(LRsave);LRsave : = null; + end;normalparagraph;@@ - 21546, 3 + 21709, 5@@@ ;SPMlt; Casesof| maincontrol| thatbuild...@ ;SPMgt; = - vmode + halign, hmode + valign : initalign; + vmode + halign, hmode + valign : + ifcurchr ;SPMgt; 0thentailappend (newmath(0, curchr)) + elseinitalign;mmode + halign : ifprivilegedthen@@ - 24882, 11 + 25047, 258@@@*

#math22#

54]System - dependentchanges. - Thissectionshouldbereplaced, ifnecessary, byanyspecial + Thefollowingsections, asrecommended, containthemoreextensivemodificationsoftheprogramthatarenecessarytomakeTEX workataparticularinstallation. - Itisusuallybesttodesignyourchangefilesothatallchangesto - previoussectionspreservethesectionnumbering;theneverybody'sversion - willbeconsistentwiththepublishedprogram.Moreextensivechanges, - whichintroducenewsections, canbeinsertedhere;thenonlytheindex - itselfwillgetanewsectionnumber.@systemdependencies@ ;SPMgt; + + @Insertsystemdependentchangeshere. + + @Lastnotleastwedothemainworkrequiredformixed - directiontexts. + Anumberofroutinesarebasedonastackofone - wordnodeswhose| info| + fieldscontain| after|,| endLcode|, or| endRcode|.Thetopofthe + stackispointedtoby| LRptr|. + + Whenthestackmanipulationmacrosofthissectionareusedbelow, + variable| LRptr| mightbetheglobalvariabledeclaredfor| shipout|, + ormightbelocalto| hpack| or| postlinebreak|. + + @dpushLR(#) = = begintempptr : = getavail;info(tempptr) : = endLRtype(#); + link(tempptr) : = LRptr;LRptr : = tempptr; + end + @dpopLR = = begintempptr : = LRptr;LRptr : = link(tempptr); + freeavail (tempptr); + end + + @ ;SPMlt; InsertLRnodesatthebeg...@ ;SPMgt; = + q : = link(temphead ); + ifLRptr ;SPMlt; ;SPMgt; nullthen + begintempptr : = LRptr;r : = q; + repeats : = newmath(0, beginLRtype(tempptr));link(s) : = r;r : = s; + tempptr : = link(tempptr); + untiltempptr = null; + link(temphead ): = r; + end; + whileq ;SPMlt; ;SPMgt; curbreak(curp)do + beginifnotischarnode(q)then@ ;SPMlt; AdjusttheLRstackforthe| p...@ ;SPMgt; ; + q : = link(q); + end + + @@ ;SPMlt; AdjusttheLRstackforthe| p...@ ;SPMgt; = + iftype(q) = mathnodethen + ifendLR(q)then + beginifLRptr ;SPMlt; ;SPMgt; nullthenifinfo(LRptr) = subtype(q)thenpopLR; + end + elsepushLR(q) + + @Weusethefactthat| q| nowpointstothenodewith˙
rightskipglue. + + @ ;SPMlt; InsertLRnodesattheend...@ ;SPMgt; = + ifLRptr ;SPMlt; ;SPMgt; nullthen + begins : = temphead;r : = link(s); + whiler ;SPMlt; ;SPMgt; qdo + begins : = r;r : = link(s); + end; + r : = LRptr; + whiler ;SPMlt; ;SPMgt; nulldo + begintempptr : = newmath(0, info(r)); + link(s) : = tempptr;s : = tempptr;r : = link(r); + end; + link(s) : = q; + end + + @@ ;SPMlt; AdjusttheLRstackforthe| h...@ ;SPMgt; = + iftype(p) = mathnodethen + ifendLR(p)then + ifsafeinfo(LRptr) = subtype(p)thenpopLR + elsebeginincr(LRproblems); + whilelink(q) ;SPMlt; ;SPMgt; pdoq : = link(q); + link(q) : = link(p);freenode(p, smallnodesize);p : = q; + end + elsepushLR(p) + + @@ ;SPMlt; CheckforLRanomaliesattheendof| h...@ ;SPMgt; = + ifLRptr ;SPMlt; ;SPMgt; nullthen + beginwhilelink(q) ;SPMlt; ;SPMgt; nulldoq : = link(q); + repeattempptr : = q;q : = newmath(0, info(LRptr));link(tempptr) : = q; + LRproblems : = LRproblems + 10000;popLR; + untilLRptr = null; + end; + ifLRproblems ;SPMgt; 0then + beginprintln;printnl (;SPMquot;#tex2html_wrap_inline206#or#tex2html_wrap_inline207#problem(;SPMquot;);@/ + printint(LRproblemsdiv10000);print(;SPMquot;missing,;SPMquot;);@/ + printint(LRproblemsmod10000);print(;SPMquot;extra;SPMquot;);@/ + LRproblems : = 0;gotocommonending; + end + + @@ ;SPMlt; Declareproceduresneededin| hlistout|,| vlistout|@ ;SPMgt; = + procedureLRconfusion; + beginconfusion(;SPMquot;LR;SPMquot;); + @ : thiscan'thappenLR<#104#><#105#>;SPMnbsp;;SPMnbsp;;SPMnbsp;;SPMnbsp;LR@;SPMgt; +end; + +@ @d LR_dir(#)==(subtype(#) div 4) <#70#>text direction of a `math node'<#70#> + +@;SPMlt;Adjust the LR stack for the |s...@;SPMgt;= +if end_LR(p) then + begin if info(LR_ptr);SPMlt;;SPMgt;subtype(p) then LR_confusion; + pop_LR; type(p):=kern_node; + end +else begin push_LR(p); type(p):=kern_node; + if LR_dir(p);SPMlt;;SPMgt;cur_dir then + begin @;SPMlt;Reverse an hlist segment containing right-to-left material@;SPMgt;; + goto reswitch; + end; + type(p):=kern_node; + end + +@ @d edge_node=style_node <#71#>a |style_node| does not occur during |ship_out|<#71#> +@d edge_node_size=style_node_size <#72#>number of words in an edge node<#72#> +@d edge_dist(#)==depth(#) <#73#>new |left_edge| position relative to |cur_h| + (after |width| has been taken into account)<#73#> + +@;SPMlt;Declare procedures needed in |hlist_out|, |vlist_out|@;SPMgt;= +function new_edge(@!s:small_number;@!w:scaled):pointer; + <#74#>create an edge node<#74#> +var p:pointer; <#75#>the new node<#75#> +begin p:=get_node(edge_node_size); type(p):=edge_node; +subtype(p):=s; width(p):=w; <#76#>the |edge_dist| field will be set later<#76#> +new_edge:=p; +end; + +@ @;SPMlt;Cases of |hlist_out| that arise...@;SPMgt;= +edge_node: begin cur_h:=cur_h+width(p); + left_edge:=cur_h+edge_dist(p); cur_dir:=subtype(p); + end; + +@ We detach the hlist, start a new one consisting of just one kern node, +append the reversed list, and set the width of the kern node. + +@;SPMlt;Reverse the complete hlist...@;SPMgt;= +begin save_h:=cur_h; temp_ptr:=p; p:=new_kern(0); link(prev_p):=p; +cur_h:=0; link(p):=reverse(this_box,null); width(p):=-cur_h; +cur_h:=save_h; type(this_box):=R_node; +end + +@ We detach the remainder of the hlist, replace the math node by +an edge node, and append the reversed hlist segment to it; the tail of +the reversed segment is another edge node and the remainder of the +original list is attached to it. + +@;SPMlt;Reverse an hlist segment...@;SPMgt;= +begin save_h:=cur_h; temp_ptr:=link(p); rule_wd:=width(p); +free_node(p,small_node_size); +cur_dir:=reflected; p:=new_edge(cur_dir,rule_wd); link(prev_p):=p; +cur_h:=cur_h-left_edge+rule_wd; +link(p):=reverse(this_box,new_edge(reflected,0)); +edge_dist(p):=cur_h; cur_dir:=reflected; cur_h:=save_h; +end + +@ The |reverse| function defined here is responsible to reverse the +nodes of an hlist (segment). The first parameter |this_box| is the +enclosing hlist node, the second parameter |t| is to become the tail of +the reversed list, and the global variable |temp_ptr| is the head of the +list to be reversed. We remove nodes from the original list and add them +to the head of the new one. + +@;SPMlt;Declare procedures needed in |hlist_out|, |vlist_out|@;SPMgt;= +function reverse(@!this_box,@!t:pointer):pointer; +label reswitch, next_p, done; +var l:pointer; <#77#>the new list<#77#> +@!p:pointer; <#78#>the current node<#78#> +@!q:pointer; <#79#>the next node<#79#> +@!g_order: glue_ord; <#80#>applicable order of infinity for glue<#80#> +@!g_sign: normal..shrinking; <#81#>selects type of glue<#81#> +@!m,@!n:halfword; <#82#>number of unmatched math nodes<#82#> +begin g_order:=glue_order(this_box); g_sign:=glue_sign(this_box); +l:=t; p:=temp_ptr; m:=min_halfword; n:=min_halfword; +while p;SPMlt;;SPMgt;null do @;SPMlt;Move node |p| to the new list and go to the next node; + or |goto done| if the end of the reflected segment has been reached@;SPMgt;; +if (t;SPMlt;;SPMgt;null)or(m;SPMlt;;SPMgt;min_halfword)or(n;SPMlt;;SPMgt;min_halfword) then LR_confusion; +done:reverse:=l; +end; + +@ @;SPMlt;Move node |p| to the new list...@;SPMgt;= +reswitch: if is_char_node(p) then + repeat f:=font(p); c:=character(p); + cur_h:=cur_h+char_width(f)(char_info(f)(c)); + q:=link(p); link(p):=l; l:=p; p:=q; + until not is_char_node(p) +else @;SPMlt;Move the non-|char_node| |p| to the new list@;SPMgt; + +@ @;SPMlt;Move the non-|char_node| |p| to the new list@;SPMgt;= +begin q:=link(p); rule_wd:=width(p); <#83#>the width is needed in most cases<#83#> +case type(p) of +hlist_node,vlist_node,rule_node,kern_node: do_nothing; +@t@;SPMgt;@;SPMlt;Cases of |reverse| that need special treatment@;SPMgt;@; +R_node,edge_node: LR_confusion; +othercases goto next_p +endcases;@/ +cur_h:=cur_h+rule_wd; +next_p: if (type(p)=kern_node)and((rule_wd=0)or(l=null)) then + free_node(p,small_node_size) +else begin link(p):=l; l:=p; + end; +p:=q; +end + +@ In order to avoid the unnecessary repetition of computations we try to +replace glue nodes by equivalent kern or rule nodes. + +@;SPMlt;Cases of |reverse|...@;SPMgt;= +glue_node: begin g:=glue_ptr(p); rule_wd:=width(g); +if g_sign;SPMlt;;SPMgt;normal then + begin if g_sign=stretching then + begin if stretch_order(g)=g_order then + rule_wd:=rule_wd+round(float(glue_set(this_box))*stretch(g)); +@^real multiplication@;SPMgt; + end + else begin if shrink_order(g)=g_order then + rule_wd:=rule_wd-round(float(glue_set(this_box))*shrink(g)); + end; + end; +temp_ptr:=leader_ptr(p); +if temp_ptr=null then + begin delete_glue_ref(g); type(p):=kern_node; width(p):=rule_wd; + end +else if type(temp_ptr)=rule_node then + begin delete_glue_ref(g); free_node(p,small_node_size); + p:=temp_ptr; width(p):=rule_wd; + end; +end; + +@ A ligature node is replaced by a char node. + +@;SPMlt;Cases of |reverse|...@;SPMgt;= +ligature_node: begin flush_node_list(lig_ptr(p)); +temp_ptr:=p; p:=get_avail; mem[p]:=mem[lig_char(temp_ptr)]; link(p):=q; +free_node(temp_ptr,small_node_size); goto reswitch; +end; + +@ Math nodes in an inner reflected segment are modified, those at the +outer level are changed into kern nodes. + +@;SPMlt;Cases of |reverse|...@;SPMgt;= +math_node: if end_LR(p) then + if n;SPMgt;min_halfword then + begin decr(n); decr(subtype(p)); <#84#>change |after| into |before|<#84#> + end + else begin if info(LR_ptr);SPMlt;;SPMgt;subtype(p) then LR_confusion; + pop_LR; + if m=min_halfword then @;SPMlt;Finish the reversed list and |goto done|@;SPMgt;; + decr(m); type(p):=kern_node; + end +else if (n;SPMgt;min_halfword)or(LR_dir(p);SPMlt;;SPMgt;cur_dir) then + begin incr(n); incr(subtype(p)); <#85#>change |before| into |after|<#85#> + end + else begin push_LR(p); incr(m); type(p):=kern_node; + end; + +@ Finally we have found the end of the hlist segment to be reversed; the +terminating math node is released and the remaining list is attached to +the edge node at the end of the reversed list. + +@;SPMlt;Finish the reversed list and |goto done|@;SPMgt;= +begin if t=null then LR_confusion; free_node(p,small_node_size); +link(t):=q; width(t):=rule_wd; edge_dist(t):=-cur_h-rule_wd; +goto done; +end

-- Dr. Zvi Har'El ;SPMlt;rl@math.technion.ac.il;SPMgt; Department of Mathematics +972-4-294094(Phone) Technion - Israel Institute of Technology +972-4-324654(FAX) Haifa 32000, ISRAEL